<template>
  <div :style="{ width: width + 'px', height: height + 'px' }">
    <canvas
      ref="verifyCanvas"
      @click="refresh"
      :width="width"
      :height="height"
      :style="{ cursor: 'pointer' }"
    ></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue"

const props = defineProps({
  width: {
    type: Number,
    default: 140
  },
  height: {
    type: Number,
    default: 42
  },
  type: {
    type: String,
    default: "blend" //图形验证码默认类型blend:数字字母混合类型、number:纯数字、letter:纯字母
  },
  //是否生成阴影
  showShadow: {
    type: Boolean,
    default: true
  },
  //是否生成干扰线
  isDrawLIne: {
    type: Boolean,
    default: true
  },
  //是否生成干扰点
  isDrawPoint: {
    type: Boolean,
    default: true
  }
})
onMounted(() => {
  refresh()
})
const numArr = "0,1,2,3,4,5,6,7,8,9".split(",")
const letterArr =
  "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".split(
    ","
  )

//获取canvas元素
const verifyCanvas = ref<HTMLCanvasElement | null>(null)

//验证码
const code = ref<string>("")

//传值
const emits = defineEmits(['updateCode'])

//生成验证码
let ctx: CanvasRenderingContext2D
const refresh = () => {
  code.value = ""
  if (verifyCanvas.value?.getContext) {
    ctx = verifyCanvas.value.getContext("2d") as CanvasRenderingContext2D
  } else {
    return false
  }
  //垂直居中
  ctx.textBaseline = "middle"
  //随机背景色
  ctx.fillStyle = randomColor(180, 240)
  //绘制矩形
  ctx.fillRect(0, 0, props.width, props.height)
  //根据类型渲染
  let txtArr: string[]
  if (props.type === "blend") {
    txtArr = numArr.concat(letterArr)
  } else if (props.type == "number") {
    txtArr = numArr
  } else {
    txtArr = letterArr
  }
  for (let i = 1; i <= 4; i++) {
    var txt = txtArr[randomNum(0, txtArr.length)]
    code.value += txt
    ctx.font = randomNum(props.height / 2, props.height) + "px SimHei" //随机生成字体大小
    ctx.fillStyle = randomColor(50, 160) //随机生成字体颜色
    //设置阴影
    if (props.showShadow) {
      ctx.shadowOffsetX = randomNum(-3, 3)
      ctx.shadowOffsetY = randomNum(-3, 3)
      ctx.shadowBlur = randomNum(-3, 3)
      ctx.shadowColor = "rgba(0, 0, 0, 0.3)"
    }
    var x = (props.width / 5) * i
    var y = props.height / 2
    var deg = randomNum(-30, 30)
    //设置旋转角度和坐标原点
    ctx.translate(x, y)
    ctx.rotate((deg * Math.PI) / 180)
    ctx.fillText(txt, 0, 0)
    /**恢复旋转角度和坐标原点**/
    ctx.rotate((-deg * Math.PI) / 180)
    ctx.translate(-x, -y)
  }
  //是否绘制干扰线
  if (props.isDrawLIne) {
    for (var i = 0; i < 4; i++) {
      ctx.strokeStyle = randomColor(40, 180)
      ctx.beginPath()
      ctx.moveTo(randomNum(0, props.width), randomNum(0, props.height))
      ctx.lineTo(randomNum(0, props.width), randomNum(0, props.height))
      ctx.stroke()
    }
  }
  //是否绘制干扰点
  if (props.isDrawPoint) {
    for (var i = 0; i < props.width / 4; i++) {
      ctx.fillStyle = randomColor(0, 255)
      ctx.beginPath()
      ctx.arc(
        randomNum(0, props.width),
        randomNum(0, props.height),
        1,
        0,
        2 * Math.PI
      )
      ctx.fill()
    }
  }
  emits('updateCode',code.value)
}
//生成随机色
const randomColor = (min: number, max: number): string => {
  let r = randomNum(min, max)
  let g = randomNum(min, max)
  let b = randomNum(min, max)
  return "rgb(" + r + "," + g + "," + b + ")"
}
//生成随机数
const randomNum = (min: number, max: number): number => {
  return Math.floor(Math.random() * (max - min) + min)
}
//暴露方法和值
defineExpose({
  refresh
})
</script>
<style lang="scss" scoped></style>
